/**
 * ConstraintAbstract
 * ----------------------------------------------
 * 
 * This abstract class represents integrity constraints for xml.
 * 
 * @author caio thomas
 */

package main.constraint;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.StringTokenizer;

import automata.Alphabet;
import automata.Fsa;
import automata.Label;
import automata.State;
import automata.StateSet;
import automata.Transitions;

public abstract class ConstraintAbstract {
	
	protected String nameConstraint; 
	protected Fsa contextFsa;
	protected Fsa sourceFsa;
	protected Fsa targetFsa;
	protected int npaths = 1;//path defines how the FSA has
	protected Hashtable<Fsa, Hashtable<State, String>> equality = new Hashtable<Fsa, Hashtable<State, String>>();
	protected ArrayList<Integer> j = new ArrayList<Integer>();
	
	public String getNameConstraint() {
		return nameConstraint;
	}
	
	public void setNameConstraint(String nameConstraint) {
		this.nameConstraint = nameConstraint;
	}
	
	public Fsa getContextFsa() {
		return contextFsa;
	}
	
	public void setContextFsa(Fsa contextFsa) {
		this.contextFsa = contextFsa;
	}
	
	public Fsa getSourceFsa() {
		return sourceFsa;
	}
	
	public void setSourceFsa(Fsa sourceFsa) {
		this.sourceFsa = sourceFsa;
	}
	
	public Fsa getTargetFsa() {
		return targetFsa;
	}
	
	public void setTargetFsa(Fsa targetFsa) {
		this.targetFsa = targetFsa;
	}
	
	public int getNpaths() {
		return npaths;
	}
	
	public void setNpaths(int npaths) {
		this.npaths = npaths;
	}
	
	public Hashtable<Fsa, Hashtable<State, String>> getEquality() {
		return equality;
	}
	
	public void setEquality(Hashtable<Fsa, Hashtable<State, String>> equality) {
		this.equality = equality;
	}
	
	public void setJ()
	{
		Iterator<State> i = sourceFsa.get_final_states().iterator();
		
		while (i.hasNext())
		{
			j.add(i.next().elt);
		}
	}
	
	public int getJ(Integer state)
	{
		return j.indexOf(state);
	}
	public String getEquality(Fsa automata, State node)
	{
		Hashtable<State, String> h;
		String tipo = null;
		
		if(equality.containsKey(automata))
		{
			h = equality.get(automata);
			tipo = h.get(node);
		}
		
		//Enumeration<Fsa> keysFsa = equality.keys();
		//Enumeration<State> keysState;
		/*while (keysFsa.hasMoreElements()) {
			Fsa f = keysFsa.nextElement();
			h = equality.get(f);
			System.out.println("Automata: "+f.toString());
			keysState = h.keys();
			while(keysState.hasMoreElements()){
				State s = keysState.nextElement();
				tipo = h.get(s);
				System.out.println("\nState: {"+s.elt+"}\nType of dependance: "+tipo);
			}
		}*/
		
		return tipo;
	}

	/**
	 * This function define type {V,N} and FSA (source or target)
	 * @param t
	 * @param automata left (l) or right (r)
	 * @return void
	 */
	public void setEquality(String t, String automata)
	{
		String [] types = t.split(",");
		Fsa f = null;
		
		if(automata.equals("l"))
			f = sourceFsa;
		if(automata.equals("r"))
			f = targetFsa;
		
		StateSet ss = f.get_final_states();
		int j = 0;
		Iterator<State> i = ss.iterator();
		Hashtable<State, String> h = new Hashtable<State, String>();
		
		while (i.hasNext() || j<types.length)
		{
			h.put(i.next(), types[j]);
			j++;
		}
		
		equality.put(f, h);
	}
	/**
	 * Function that creates FSA (automaton) from a path
	 * @param path
	 * @return new FSA
	 */
	public Fsa pathToFsa(String path)
	{
		//System.out.println("Path To FSA: " + path);
		Fsa f = new Fsa();
		int i = 1;

		Label star = new Label("*");
		State start = new State(1);
		State sant;
		State s;
		Alphabet alpha = new Alphabet();
		StateSet ss = new StateSet();
		StateSet fs = new StateSet();
		Transitions t = new Transitions();
		String token = new String();

		ss.add(start);
		sant = start;
		StringTokenizer st = new StringTokenizer(path, " ");
		
		while (st.hasMoreTokens())
		{
			token = st.nextToken();
			if (token.equals("|"))
			{
				fs.add(sant);
				sant = start;
			}

			if (token.equals("//"))
			{
				alpha.add(star);
				StateSet ss2 = new StateSet();
				ss2.add(sant);
				t.put(sant, star, ss2);
			}

			if ((!token.equals("/")) && (!token.equals("//")) && (!token.equals("|")))
			{
				Label l = new Label(token);
				if(alpha.contains(l))
				{
					sant = new State (sant.elt+1);
				}
				else
				{
					i++;
					alpha.add(l);
					s = new State(i);
					ss.add(s);
					StateSet ss1 = new StateSet();
					ss1.add(s);
					t.put(sant, l, ss1);
					sant = s;
				}
			}

		}
		
		fs.add(sant);
		f.set_alphabet(alpha);
		f.set_states(ss);
		f.set_start_state(start);
		f.set_final_states(fs);
		f.set_transitions(t);
		
		return f;
	}
	
	public abstract String toString();
	
	public abstract String toStringWeb();
	
}
